package com.hn.kiss.modules.sys.security;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hn.kiss.config.compoent.JwtAuthenticationTokenFilter;
import com.hn.kiss.config.compoent.RestAuthenticationEntryPoint;
import com.hn.kiss.config.compoent.RestfulAccessDeniedHandler;
import com.hn.kiss.modules.sys.entity.User;
import com.hn.kiss.modules.sys.entity.UserRole;
import com.hn.kiss.modules.sys.mapper.UserMapper;
import com.hn.kiss.modules.sys.service.IRoleJurisdictionService;
import com.hn.kiss.modules.sys.service.IUserRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.List;


/**
 * SpringSecurity的配置
 * Created by macro on 2018/4/26.
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private UserMapper userMapper;
    @Autowired
    private IRoleJurisdictionService roleJurisdictionService;
    @Autowired
    private IUserRoleService userRoleService;


    //拦截配合
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf()// 由于使用的是JWT，我们这里不需要csrf
                .disable()
                .sessionManagement()// 基于token，所以不需要session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET,
                        "/swagger-ui.html/**",
                        "/swagger-resources/**",
                        "/webjars/**",
                        "/v2/**",
                        "/js/**",
                        "/layui/**",
                        "/css/**",
                        "/user/login",
                        "/user/adminRegister",
                        "/dictDetail/listAll"
                ).permitAll()// 允许对于网站静态资源的无授权访问
                .antMatchers(HttpMethod.OPTIONS).permitAll();//跨域请求会先进行一次options请求
        //测试环境不拦截
        httpSecurity.authorizeRequests().anyRequest().permitAll();
        //拼接权限的拦截,对所有维护的权限进行拦截
        /*List<Jurisdiction> sysJurisdictions = jurisdictionService.list();
        if (sysJurisdictions != null && sysJurisdictions.size() > 0) {
            for (Jurisdiction jurisdiction : sysJurisdictions) {
                httpSecurity.authorizeRequests().antMatchers(jurisdiction.getUrl()).hasAuthority(jurisdiction.getUrl());
            }
        }*/
        //其他的需要登录
//        httpSecurity.authorizeRequests().anyRequest().authenticated();

        // 禁用缓存
        httpSecurity.headers().cacheControl();
        // 添加JWT filter
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        httpSecurity.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler())
                .authenticationEntryPoint(restAuthenticationEntryPoint());
    }

    //认证授权
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }


    //密码加密
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    //这里相当于实现UserDetailsService的接口,在登陆的时候调用,接口参数username,roleCode
    @Bean
    public MyUserDetailsService myUserDetailsService() {
        return (userName,roleCode) -> {
            //这里应该通过数据,根据用户名查询用户信息
             LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda()
                        .eq(User::getPhone, userName)
                        .or().eq(User::getIdno, userName)
                        .or().eq(User::getEmall, userName);
            User user = userMapper.selectOne(lambda);
            if (user == null)
                throw new UsernameNotFoundException("用户名有误");

            //登录没有传role,取用户默认角色
            if (StringUtils.isBlank(roleCode)) {
                UserRole one = userRoleService.getOne(Wrappers.<UserRole>lambdaQuery()
                        .eq(UserRole::getUserId, user.getId())
                        .eq(UserRole::getSign, "1"));
                roleCode = one==null?null:one.getRoleCode();
            }

            List<String> juris = roleJurisdictionService.listJuriUrlByRole(roleCode);
            return new AdminUserDetails(user, roleCode, juris);
        };
    }

    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }
    @Bean
    public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
        return new RestfulAccessDeniedHandler();
    }
    @Bean
    public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
        return new RestAuthenticationEntryPoint();
    }

    /**
     * 允许跨域调用的过滤器
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return new CorsFilter(source);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }





}
